package control

import (
	"jvm/instructions/base"
	"jvm/rtda"
)

// Return void from method
type RETURN struct{ base.NoOperandsInstruction }

func (r *RETURN) Execute(jFrame *rtda.JFrame) {
	jFrame.JThread().PopJFrame()
}

// Return reference from method
type ARETURN struct{ base.NoOperandsInstruction }

func (r *ARETURN) Execute(jFrame *rtda.JFrame) {
	thread := jFrame.JThread()
	currentJFrame := thread.PopJFrame()
	invokerJFrame := thread.TopJFrame()
	ref := currentJFrame.OperandStack().PopRef()
	invokerJFrame.OperandStack().PushRef(ref)
}

// Return double from method
type DRETURN struct{ base.NoOperandsInstruction }

func (r *DRETURN) Execute(jFrame *rtda.JFrame) {
	thread := jFrame.JThread()
	currentJFrame := thread.PopJFrame()
	invokerJFrame := thread.TopJFrame()
	val := currentJFrame.OperandStack().PopDouble()
	invokerJFrame.OperandStack().PushDouble(val)
}

// Return float from method
type FRETURN struct{ base.NoOperandsInstruction }

func (r *FRETURN) Execute(jFrame *rtda.JFrame) {
	thread := jFrame.JThread()
	currentJFrame := thread.PopJFrame()
	invokerJFrame := thread.TopJFrame()
	val := currentJFrame.OperandStack().PopFloat()
	invokerJFrame.OperandStack().PushFloat(val)
}

// Return int from method
type IRETURN struct{ base.NoOperandsInstruction }

func (r *IRETURN) Execute(jFrame *rtda.JFrame) {
	thread := jFrame.JThread()
	currentJFrame := thread.PopJFrame()
	invokerJFrame := thread.TopJFrame()
	val := currentJFrame.OperandStack().PopInt()
	invokerJFrame.OperandStack().PushInt(val)
}

// Return double from method
type LRETURN struct{ base.NoOperandsInstruction }

func (r *LRETURN) Execute(jFrame *rtda.JFrame) {
	thread := jFrame.JThread()
	currentJFrame := thread.PopJFrame()
	invokerJFrame := thread.TopJFrame()
	val := currentJFrame.OperandStack().PopLong()
	invokerJFrame.OperandStack().PushLong(val)
}
